﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Arroguella.Entities;
using Arroguella.Tiles;

namespace Arroguella
{
    /// <summary>
    /// Simple class to manage the player's inventory
    /// </summary>
    public class Inventory
    {
        #region Constructor

        public Inventory(Player player)
        {
            Player = player;

            EntityNames = new Dictionary<string, Entity>();
            EntityQuantities = new Dictionary<string, int>();
        }

        #endregion

        #region Methods

        /// <summary>
        /// Gets a certain entity and adds it to the player's inventory.
        /// (As long as the player can carry it!)
        /// </summary>
        public bool Get(Entity entity)
        {
            if (entity.Weight + Player.CurrentCarriedWeight <= Player.CarryingCapacity)
            {
                if (AddToInventory(entity))
                {
                    Console.WriteLine(string.Format("Player added {0} to inventory. Current Carried Weight: {1} kg / Carrying Capacity: {2} kg",
                     entity.Name, Player.CurrentCarriedWeight, Player.CarryingCapacity));
                    return true;
                }
            }

            return false;
        }

        /// <summary>
        /// Gets all the entities from a tile and adds it to the player's inventory.
        /// (As long as the player can carry them!)
        /// </summary>
        public bool GetAll(Tile tile)
        {
            bool success = true;

            if (tile.Objects.Count == 0)
            {
                return false;
            }

            foreach (Entity entity in tile.Objects)
            {
                success &= Get(entity);
            }

            return success;
        }

        /// <summary>
        /// Drops an entity from the player's inventory.
        /// </summary>
        public Entity Drop(string entityName)
        {
            Entity entity;
            TryGetEntity(entityName, out entity);
            if (entity != null)
            {
                Drop(entity);
                return entity;
            }

            return null;
        }

        /// <summary>
        /// Drops an entity from the player's inventory.
        /// </summary>
        public void Drop(Entity entity)
        {
            RemoveFromInventory(entity.Name);
            Console.WriteLine(string.Format("Player dropped {0} from inventory. Current Carried Weight: {1} kg / Carrying Capacity: {2} kg",
                    entity.Name, Player.CurrentCarriedWeight, Player.CarryingCapacity));
        }

        /// <summary>
        /// Attempts to add an Entity to the Inventory.
        /// If this type of Entity already exists, we increase its quantity.
        /// </summary>
        /// <param name="entity">The entity to be added</param>
        /// <returns>True if we were successful, false otherwise.</returns>
        internal bool AddToInventory(Entity entity)
        {
            Player.CurrentCarriedWeight += entity.Weight;

            if (EntityQuantities.ContainsKey(entity.Name))
            {
                EntityQuantities[entity.Name] += 1;
            }
            else
            {
                EntityNames.Add(entity.Name, entity);
                EntityQuantities.Add(entity.Name, 1);
            }

            return true;
        }

        /// <summary>
        /// Tries to get a reference to the Entity in Inventory.
        /// This does NOT remove the Entity from Inventory.
        /// </summary>
        public void TryGetEntity(string name, out Entity entity)
        {
            if (EntityNames.ContainsKey(name) && EntityQuantities.ContainsKey(name))
            {
                entity = EntityNames[name];
            }
            else
            {
                entity = null;
            }
        }

        /// <summary>
        /// Removes an Entity from Inventory.
        /// If this reduces that Entity's quantity to 0,
        /// we remove all references to it here. 
        /// </summary>
        /// <param name="name">The name of the Entity to be removed.</param>
        /// <returns>The Entity specified.</returns>
        internal Entity RemoveFromInventory(string name)
        {
            if (EntityQuantities.ContainsKey(name))
            {
                Entity entity = EntityNames[name];
                EntityQuantities[name] -= 1;
                Player.CurrentCarriedWeight -= entity.Weight;

                if (EntityQuantities[name] == 0)
                {
                    EntityQuantities.Remove(name);
                    EntityNames.Remove(name);
                }

                return entity;
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region Properties

        private Player Player;

        public Dictionary<string, Entity> EntityNames { get; set; }

        public Dictionary<string, int> EntityQuantities { get; set; } 

        #endregion
    }
}
